package com.ticket.sass.admin.business.impl;


import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ticket.sass.admin.business.CommodityBusiness;
import com.ticket.sass.admin.dto.input.commodity.*;
import com.ticket.sass.admin.dto.output.commodity.CommodityInfoOutput;
import com.ticket.sass.admin.dto.output.commodity.CommodityListOutput;
import com.ticket.sass.admin.dto.output.commodity.CommoditySkuOutput;
import com.ticket.sass.admin.model.PageModel;
import com.ticket.sass.admin.service.impl.*;
import com.ticket.sass.admin.util.*;
import com.ticket.sass.common.entity.tenant.CommodityEntity;
import com.ticket.sass.common.entity.tenant.CommoditySkuAttrValueMapEntity;
import com.ticket.sass.common.entity.tenant.CommoditySkuEntity;
import com.ticket.sass.common.entity.tenant.enums.CommodityPublishStatus;
import com.ticket.sass.common.exception.enums.ErrorCode;
import com.ticket.sass.common.exception.exception.BadRequestException;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ywb
 * @date 2023-04-03 17:53
 */
@Service
@AllArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class  CommodityBusinessImpl implements CommodityBusiness {
    
    final FileUtil fileUtil;
    final ModelUtil modelUtil;
    final CommodityServiceImpl commodityService;
    final CommoditySkuServiceImpl commoditySkuService;
    final CommoditySkuAttrServiceImpl commoditySkuAttrService;
    final CommoditySkuAttrValueServiceImpl commoditySkuAttrValueService;
    final CommoditySkuAttrValueMapServiceImpl commoditySkuAttrValueMapService;
    
    @Override
    public PageModel<CommodityListOutput> list(CommodityListInput input) {
        IPage<CommodityEntity> page = commodityService.iPage(input);
        
        List<Long> commodityIds = page.getRecords().stream().map(CommodityEntity::getId).collect(Collectors.toList());
        
        Map<Long, List<CommoditySkuEntity>> mapByCommodityIds = commoditySkuService.mapByCommodityIds(commodityIds);
        
        List<CommodityListOutput> collect = page.getRecords().stream().map(
            commoditiesEntity -> CommodityListOutput.buildFromEntities(commoditiesEntity, mapByCommodityIds.getOrDefault(commoditiesEntity.getId(), new ArrayList<>()))
        ).collect(Collectors.toList());
        
        return new PageModel<>(page.getTotal(), collect);
    }
    
    @Override
    public void add(CommodityAddInput input) {
        Long cinemaId = CinemaIdUtil.getCinemaIdFromRequest();
        
        CommodityEntity commodity = createEntity(input);
        commodityService.save(commodity);
        
        processCommoditySkus(commodity.getId(), cinemaId, input.getCommoditySkus());
    }
    
    private CommodityEntity createEntity(CommodityAddInput input) {
        List<String> cover = input.getCover().stream().map(fileUtil::tempToFormal).collect(Collectors.toList());
        CommodityEntity commodity = modelUtil.mapToMap(input, CommodityEntity.class);
        
        commodity.setCover(cover.isEmpty() ? "[]" : GsonUtil.getInstance().toJson(cover));
        commodity.setPublishStatus(CommodityPublishStatus.Companion.valueOf(input.getPublishStatus()));
        return commodity;
    }
    
    @Override
    public CommodityInfoOutput info(Long id) {
        // 校验卖品
        validateCommodity(id);
        // 生产简单数据
        List<CommoditySkuEntity> commoditySkusEntities = commoditySkuService.listByCommodityId(id);
        
        CommodityInfoOutput output = CommodityInfoOutput.buildFromEntities(commodityService.getById(id), commoditySkusEntities);
        // 规格
        List<CommoditySkuOutput> data = commoditySkusEntities.stream().map(CommoditySkuOutput::new).collect(Collectors.toList());
        
        // sku id
        List<Long> skuIds = data.stream().map(CommoditySkuOutput::getId).collect(Collectors.toList());
        
        Map<Long, Map<String, String>> skuAttrMap = commoditySkuAttrValueMapService.selectAttrAndValueBySkuIds(skuIds);
        
        // 创建一个新的 Map，用于存储聚合后的属性值
        Map<String, Set<String>> aggregatedAttrMap = new HashMap<>();
        
        // 遍历每个 SKU
        data.forEach(sku -> {
            // 获取当前 SKU 的属性名和属性值的 Map
            Map<String, String> attrMap = skuAttrMap.getOrDefault(sku.getId(), new HashMap<>());
            sku.setAttrMap(attrMap);
            
            // 遍历当前 SKU 的属性名和属性值
            attrMap.forEach((attrName, attrValue) -> {
                // 检查聚合的 Map 中是否已存在当前属性名
                if (aggregatedAttrMap.containsKey(attrName)) {
                    // 如果已存在，则将当前属性值添加到对应的 Set 中
                    aggregatedAttrMap.get(attrName).add(attrValue);
                } else {
                    // 如果不存在，则创建一个新的 Set，并将当前属性值添加到 Set 中
                    Set<String> attrValues = new HashSet<>();
                    attrValues.add(attrValue);
                    aggregatedAttrMap.put(attrName, attrValues);
                }
            });
        });
        
        output.setAggregatedAttrMap(aggregatedAttrMap);
        output.setCommoditySkus(data);
        return output;
    }
    
    @Override
    public void publish(PublishInput input) {
        validateCommodity(input.getId());
     
        // 商品 上架
        commodityService.update(new UpdateWrapper<CommodityEntity>().set("publish_status", CommodityPublishStatus.PUBLISHED.getValue()).eq("id", input.getId()));
    }
    
    @Override
    public void unpublished(PublishInput input) {
        validateCommodity(input.getId());
        // 商品 下架
        commodityService.update(new UpdateWrapper<CommodityEntity>().set("publish_status", CommodityPublishStatus.UNPUBLISH.getValue()).eq("id", input.getId()));
    }
    
    
    @Override
    public void upd(CommodityUpdInput input) {
        // 校验卖品
        validateCommodity(input.getId());
        
        // 创建并更新卖品实体
        CommodityEntity commodity = createEntity(input);
        commodityService.updateById(commodity);
        
        // 修改规格
        updateCommoditySkus(input);
    }
    
    private void updateCommoditySkus(CommodityUpdInput input) {
        List<CommoditySkuInput> commoditySkus = input.getCommoditySkus();
        // 过滤 ID 不为空的数据 这样在查询数据库时回爆出异常 规格不允许为空
        List<Long> ids = commoditySkus.stream()
            .map(CommoditySkuInput::getId)
            .filter(Objects::nonNull)
            .collect(Collectors.toList());

        
        
        Long count = commoditySkuService.countBy(ids, input.getId());
        if (count != ids.size()) {
            throw new BadRequestException(
                ErrorCode.BUSINESS_ERROR,
                EscapeUtil.errorMessage("commoditySkus", "规格不允许修改")
            );
        }
        
        List<CommoditySkuEntity> updateList = commoditySkus.stream()
            .map(this::mapToCommoditySkusEntity)
            .collect(Collectors.toList());
        
        commoditySkuService.updateBatchById(updateList);
    }

    
    private CommodityEntity createEntity(CommodityUpdInput input) {
        CommodityEntity commodity = modelUtil.mapToMap(input, CommodityEntity.class);
        List<String> cover = input.getCover().stream().map(fileUtil::tempToFormal).collect(Collectors.toList());
        commodity.setPublishStatus(CommodityPublishStatus.Companion.valueOf(input.getPublishStatus()));
        commodity.setCover(cover.isEmpty() ? "[]" : GsonUtil.getInstance().toJson(cover));
        return commodity;
    }
    
    private void validateCommodity(Long id) {
        boolean areValid = commodityService.isEmpty(id);
        if (areValid) {
            throw new BadRequestException(
                ErrorCode.RECORD_NOT_EXIST,
                EscapeUtil.errorMessage("id", "卖品不存在")
            );
        }
    }
    
    // 处理商品SKU列表
    public void processCommoditySkus(Long commodityId, Long cinemaId, List<CommoditySkuInput> commoditySkus) {
        // 如果只有一个商品SKU
        if (commoditySkus.size() == 1) {
            // 处理单个商品SKU
            processSingleCommoditySku(commodityId, cinemaId, commoditySkus.get(0));
        } else {
            // 处理多个商品SKU
            commoditySkus.forEach(
                sku -> processSingleCommoditySku(commodityId, cinemaId, sku)
            );
        }
    }
    
    // 处理单个商品SKU
    private void processSingleCommoditySku(Long commodityId, Long cinemaId, CommoditySkuInput commoditySku) {
        // 将商品SKU对象映射为实体对象
        CommoditySkuEntity skuEntity = mapToCommoditySkusEntity(commoditySku);
        skuEntity.setCommodityId(commodityId);
        skuEntity.setCinemaId(cinemaId);
 
        // 如果商品SKU包含属性
        if (commoditySku.getAttrMap() != null && !commoditySku.getAttrMap().isEmpty()) {
            // 有规格
            skuEntity.setHasAttr(true);
            // 保存商品SKU实体
            commoditySkuService.save(skuEntity);
            // 处理商品SKU的属性
            processCommoditySkuAttributes(commodityId, cinemaId, skuEntity.getId(), commoditySku);
        } else {
            // 没有规格
            skuEntity.setHasAttr(false);
            // 保存商品SKU实体
            commoditySkuService.save(skuEntity);
        }
    }
    
    // 将商品SKU对象映射为实体对象
    private CommoditySkuEntity mapToCommoditySkusEntity(CommoditySkuInput input) {
        List<String> cover = input.getCover().stream().map(fileUtil::tempToFormal).collect(Collectors.toList());
        
        CommoditySkuEntity commoditySku = modelUtil.mapToMap(input, CommoditySkuEntity.class);
        commoditySku.setCover(cover.size() == 0 ? "[]" : GsonUtil.getInstance().toJson(cover));
        return commoditySku;
    }
    
    // 处理商品SKU的属性
    private void processCommoditySkuAttributes(Long commodityId, Long cinemaId, Long skuId, CommoditySkuInput commoditySku) {
        // 获取商品SKU的属性映射
        Map<String, String> attrMap = commoditySku.getAttrMap();
        // 获取属性列表
        Set<String> attrs = attrMap.keySet();
        // 遍历属性列表
        attrs.forEach(attr -> {
            // 创建保存商品SKU属性
            Long attrId = commoditySkuAttrService.getOrCreateAttrId(attr, commodityId, cinemaId);
            
            // 创建保存商品SKU属性值
            Long attrValueId = commoditySkuAttrValueService.getOrCreateAttrValueId(attrId, attrMap.get(attr), commodityId, cinemaId);
            
            // 创建商品SKU属性关联
            commoditySkuAttrValueMapService.save(new CommoditySkuAttrValueMapEntity(skuId, attrId, attrValueId, cinemaId));
        });
    }
}
